package org.googlecode.viewt.core.tools;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import xjavadoc.SourceClass;
import xjavadoc.Type;
import xjavadoc.XConstructor;
import xjavadoc.XJavaDoc;
import xjavadoc.XMethod;
import xjavadoc.XParameter;
import xjavadoc.XTagFactory;
import xjavadoc.filesystem.AbstractFile;
import xjavadoc.filesystem.FileSourceSet;

public class JavaSourceParser
{
  private final static Logger logger = LoggerFactory.getLogger(JavaSourceParser.class);
  public static final String DEFAULT_ENC = "GB2312";

  public static SourceClass[] parseFile(String javaFile)
  {
    File targetFile = new File(javaFile);
    if (!(targetFile.exists()))
    {
      logger.error("specified source file:" + javaFile + " does not exists!");
      return null;
    }

    List classList = new ArrayList();
    FileSourceSet targetSet = new FileSourceSet(targetFile);

    int targetSize = targetSet.getSize();
    for (int i = 0; i < targetSize; ++i)
    {
      AbstractFile sourceFile = targetSet.getSourceFile(targetSet.getQualifiedName(i));
      classList.add(new SourceClass(new XJavaDoc(), sourceFile, true, new XTagFactory(), "GB2312"));
    }

    return ((SourceClass[])classList.toArray(new SourceClass[0]));
  }

//  public static boolean validateParams(XMethod[] methods, LogicDescRepository logicRepository)
//  {
//    int size = (methods == null) ? 0 : methods.length;
//    for (int i = 0; i < size; ++i)
//    {
//      logger.info("validate webservice method:" + methods[i].getName());
//
//      if (isBeanType(methods[i].getReturnType()))
//      {
//        XClass beanClass = logicRepository.getBLClass(methods[i].getReturnType().getType().getQualifiedName());
//        if (beanClass == null) {
//          beanClass = methods[i].getReturnType().getType();
//        }
//        if ((beanClass.isAbstract()) || (beanClass.isInterface())) {
//          return false;
//        }
//      }
//
//      List paramList = methods[i].getParameters();
//      int count = (paramList == null) ? 0 : paramList.size();
//      for (int j = 0; j < count; ++j)
//      {
//        Type paramType = (Type)paramList.get(j);
//        if (!(isBeanType(paramType)))
//          continue;
//        XClass beanClass = logicRepository.getBLClass(paramType.getType().getQualifiedName());
//        if (beanClass == null) {
//          beanClass = paramType.getType();
//        }
//        if ((beanClass.isAbstract()) || (beanClass.isInterface())) {
//          return false;
//        }
//      }
//    }
//
//    return true;
//  }

  public static boolean validateBLClass(SourceClass intClass, SourceClass impClass)
  {
    if (intClass == null)
    {
      logger.error("Empty interface class, maybe parse interface fail");
      return false;
    }
    if (impClass == null)
    {
      logger.error("Empty implement class, maybe parse implement fail");
      return false;
    }

    if (!(intClass.isInterface()))
    {
      logger.error("Invalid interface:" + intClass.getQualifiedName());
      return false;
    }

    if ((impClass.isAbstract()) || (impClass.isInner()) || (impClass.isInterface()) || (impClass.isPrimitive()))
    {
      logger.error("Invalid implement:" + impClass.getQualifiedName());
      return false;
    }

    if (!(impClass.isImplementingInterface(intClass.getQualifiedName())))
    {
      logger.error("Specified class:" + impClass.getQualifiedName() + " not implement interface:" + intClass.getQualifiedName());
      return false;
    }

    XConstructor constructor = impClass.getConstructor(impClass.getName() + "()");
    if (constructor == null)
    {
      logger.error("Specified class:" + impClass.getQualifiedName() + " has no default constructor");
      return false;
    }
    if (!(constructor.isPublic()))
    {
      logger.error("Constructor of specified class:" + impClass.getQualifiedName() + " is not public");
      return false;
    }

    return true;
  }

  public static XMethod[] getMethods(SourceClass intClass, String[] incMethods, String[] excMethods)
  {
    if (intClass == null) {
      return null;
    }
    List methodList = new ArrayList();
    if ((incMethods != null) && (incMethods.length > 0))
    {
      for (int i = 0; i < incMethods.length; ++i)
      {
        XMethod method = intClass.getMethod(incMethods[i].trim());
        if (method == null)
        {
          logger.error("Specified include method:" + incMethods[i] + " not found in " + intClass.getQualifiedName());
        }
        else if ((method.isPublic()) && (!("setDaoTransaction".equals(method.getName()))))
          methodList.add(method);
        else
          logger.error("Specified include method:" + incMethods[i] + " is not public");
      }
    }
    else
    {
      List allMethods;
      int size;
      int i;
      XMethod method;
      if ((excMethods != null) && (excMethods.length > 0))
      {
        allMethods = intClass.getMethods(true);
        size = (allMethods == null) ? 0 : allMethods.size();
        for (i = 0; i < size; ++i)
        {
          method = (XMethod)allMethods.get(i);
          if (!(method.isPublic())) continue; if ("setDaoTransaction".equals(method.getName())) {
            continue;
          }
          int j = 0;
          for (j = 0; j < excMethods.length; ++j)
          {
            if (!(excMethods[j].equals(methodSignature(method, false))))
              continue;
            logger.debug("Method:" + methodSignature(method, false) + " in exclude list, ignore it");
            break;
          }

          if (j == excMethods.length) {
            methodList.add(method);
          }
        }
      }
      else
      {
        allMethods = intClass.getMethods(true);
        size = (allMethods == null) ? 0 : allMethods.size();
        for (i = 0; i < size; ++i)
        {
          method = (XMethod)allMethods.get(i);
          if ((method.isPublic()) && (!("setDaoTransaction".equals(method.getName()))))
            methodList.add(method);
        }
      }
    }
    return ((XMethod[])methodList.toArray(new XMethod[0]));
  }

  public static String methodSignature(XMethod method, boolean withParam)
  {
    if (null == method) {
      return null;
    }
    StringBuffer buf = new StringBuffer(method.getName());
    List parameters = method.getParameters();
    int paramCount = (null == parameters) ? 0 : parameters.size();
    for (int i = 0; i < paramCount; ++i) {
      ((XParameter)parameters.get(i)).getType();
    }
    buf.append("(");
    for (int i = 0; i < paramCount; ++i)
    {
      if (i > 0)
        buf.append(",");
      XParameter param = (XParameter)parameters.get(i);
      buf.append(param.getType().getQualifiedName());
      buf.append(param.getDimensionAsString());
      if (withParam)
        buf.append(" ").append(param.getName());
    }
    buf.append(")");

    return buf.toString();
  }

//  public static String[] getParamBeans(XMethod[] methods)
//  {
//    return getParamBeans(methods, null);
//  }
//
//  public static String[] getParamBeans(XMethod[] methods, LogicDescRepository repository)
//  {
//    List beanClassList = new ArrayList();
//
//    int size = (methods == null) ? 0 : methods.length;
//    for (int i = 0; i < size; ++i)
//    {
//      XMethod method = methods[i];
//
//      if (isBeanType(method.getReturnType())) {
//        addBeanClass(beanClassList, method.getReturnType().getType().getQualifiedName(), repository);
//      }
//      List paramList = method.getParameters();
//      int count = (paramList == null) ? 0 : paramList.size();
//      for (int j = 0; j < count; ++j)
//      {
//        Type paramType = (Type)paramList.get(j);
//        if (isBeanType(paramType)) {
//          addBeanClass(beanClassList, paramType.getType().getQualifiedName(), repository);
//        }
//      }
//    }
//    return ((String[])beanClassList.toArray(new String[0]));
//  }

  public static boolean isBeanType(Type type)
  {
    if (type == null) {
      return false;
    }
    if (type.getType().isPrimitive()) {
      return false;
    }
    String className = type.getType().getQualifiedName();

    return ((className.equals("void")) || (className.startsWith("java.")) || (className.startsWith("javax.")));
  }

//  public static boolean isBeanField(String fieldName, XField field, SourceClass beanClass)
//  {
//    if ((null == fieldName) || (null == field) || (null == beanClass)) {
//      return false;
//    }
//    String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
//    String setMethodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
//    String booleanGetMethod = "is" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
//    boolean booleanType = "boolean".equals(field.getType().getQualifiedName());
//
//    XMethod method = beanClass.getMethod(setMethodName + "(" + field.getType().getQualifiedName() + field.getDimensionAsString() + ")", true);
//    if ((null == method) || (!(method.isPublic()))) {
//      return false;
//    }
//
//    method = beanClass.getMethod(getMethodName + "()", true);
//    if ((null != method) && (method.isPublic())) {
//      return true;
//    }
//
//    if (!(booleanType))
//      break label312;
//    method = beanClass.getMethod(booleanGetMethod + "()", true);
//
//    label312: return ((null == method) || (!(method.isPublic())));
//  }

//  public static boolean isBeanField(XField field, SourceClass beanClass)
//  {
//    if ((null == field) || (null == beanClass)) {
//      return false;
//    }
//    String fieldName = field.getName();
//    if (!(isBeanField(fieldName, field, beanClass)))
//    {
//      int index = 0;
//      while (fieldName.charAt(index) == '_') {
//        ++index;
//      }
//      if (index > 0) {
//        return isBeanField(fieldName.substring(index), field, beanClass);
//      }
//      return false;
//    }
//
//    return true;
//  }

	// protected static void addBeanClass(List classList, String className)
	// {
	// addBeanClass(classList, className, null);
	// }
	//
	// protected static void addBeanClass(List classList, String className,
	// LogicDescRepository repository)
	// {
	// if (className == null)
	// return;
	// if (classList.contains(className)) {
	// return;
	// }
	// classList.add(className);
	// if (logger.isDebugEnabled()) {
	// logger.debug("class:" + className + " add to bean list");
	// }
	//
	// if (null == repository) {
	// logger.debug("java source repository is null");
	// }
	// SourceClass beanClass = (null == repository) ? null :
	// repository.getBLClass(className);
	// if (null == beanClass)
	// {
	// if (logger.isDebugEnabled())
	// logger.debug("java source for class:" + className +
	// " not found in repository, can not analysis");
	// return;
	// }
	//
	// if (logger.isDebugEnabled()) {
	// logger.debug("checking properties of bean class:" + className);
	// }
	// List fieldList = beanClass.getFields(true);
	// int len = (null == fieldList) ? 0 : fieldList.size();
	// for (int i = 0; i < len; ++i)
	// {
	// XField field = (XField)fieldList.get(i);
	// if (logger.isDebugEnabled()) {
	// logger.debug("checking field:" + field.getName() + " of class:" +
	// className);
	// }
	// if ((isBeanType(field)) && (isBeanField(field, beanClass)))
	// addBeanClass(classList, field.getType().getQualifiedName(), repository);
	// }
	// }
}